package com.library.management.repository;

import com.library.management.entity.Fine;
import com.library.management.entity.User;
import com.library.management.enums.FineReason;
import com.library.management.enums.FineStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 罚款记录数据访问层接口
 * 提供罚款记录相关的数据库操作
 *
 * @author 开发者
 * @version 1.0
 * @since 2025-10-20
 */
@Repository
public interface FineRepository extends JpaRepository<Fine, Long> {

    // ========== 用户相关查询 ==========

    /**
     * 根据用户查找罚款记录
     *
     * @param user 用户
     * @return 罚款记录列表
     */
    List<Fine> findByUser(User user);

    /**
     * 根据用户ID查找罚款记录
     *
     * @param userId 用户ID
     * @return 罚款记录列表
     */
    List<Fine> findByUserId(Long userId);

    /**
     * 根据用户和状态查找罚款记录
     *
     * @param user 用户
     * @param status 罚款状态
     * @return 罚款记录列表
     */
    List<Fine> findByUserAndStatus(User user, FineStatus status);

    // ========== 状态相关查询 ==========

    /**
     * 根据罚款状态查找记录
     *
     * @param status 罚款状态
     * @return 罚款记录列表
     */
    List<Fine> findByStatus(FineStatus status);

    /**
     * 根据多个罚款状态查找记录
     *
     * @param statuses 罚款状态列表
     * @return 罚款记录列表
     */
    List<Fine> findByStatusIn(List<FineStatus> statuses);

    // ========== 原因相关查询 ==========

    /**
     * 根据罚款原因查找记录
     *
     * @param reason 罚款原因
     * @return 罚款记录列表
     */
    List<Fine> findByFineReason(FineReason reason);

    /**
     * 根据用户和罚款原因查找记录
     *
     * @param user 用户
     * @param reason 罚款原因
     * @return 罚款记录列表
     */
    List<Fine> findByUserAndFineReason(User user, FineReason reason);

    // ========== 时间相关查询 ==========

    /**
     * 查找创建时间在指定范围内的罚款记录
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 罚款记录列表
     */
    List<Fine> findByCreatedTimeBetween(LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 查找支付日期在指定范围内的罚款记录
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 罚款记录列表
     */
    List<Fine> findByPaymentDateBetween(LocalDateTime startDate, LocalDateTime endDate);

    // ========== 复杂查询方法 ==========

    /**
     * 统计用户的罚款总金额
     *
     * @param userId 用户ID
     * @return 罚款总金额
     */
    @Query("SELECT SUM(f.fineAmount) FROM Fine f WHERE f.user.id = :userId")
    Optional<BigDecimal> sumFineAmountByUserId(@Param("userId") Long userId);

    /**
     * 统计用户的未支付罚款金额
     *
     * @param userId 用户ID
     * @return 未支付罚款金额
     */
    @Query("SELECT SUM(f.fineAmount - f.paidAmount) FROM Fine f WHERE f.user.id = :userId AND f.status IN ('UNPAID', 'PARTIAL')")
    Optional<BigDecimal> sumUnpaidFineAmountByUserId(@Param("userId") Long userId);

    /**
     * 查找金额大于指定值的罚款记录
     *
     * @param amount 金额阈值
     * @return 罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.fineAmount > :amount")
    List<Fine> findFinesWithAmountGreaterThan(@Param("amount") BigDecimal amount);

    /**
     * 统计各状态的罚款数量
     */
    @Query("SELECT f.status, COUNT(f) FROM Fine f GROUP BY f.status")
    List<Object[]> countFinesByStatus();

    /**
     * 查找逾期未支付的罚款记录（创建时间超过指定天数）
     *
     * @param thresholdTime 阈值时间
     * @return 逾期罚款记录
     */
    @Query("SELECT f FROM Fine f WHERE f.status IN ('UNPAID', 'PARTIAL') AND f.createdTime < :thresholdTime")
    List<Fine> findOverdueFines(@Param("thresholdTime") LocalDateTime thresholdTime);

    /**
     * 根据借阅记录ID查找罚款记录
     *
     * @param borrowRecordId 借阅记录ID
     * @return 罚款记录
     */
    Optional<Fine> findByBorrowRecordId(Long borrowRecordId);

    /**
     * 查找指定天数内创建的罚款记录
     *
     * @param startTime 开始时间
     * @return 罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.createdTime >= :startTime")
    List<Fine> findFinesCreatedInLastDays(@Param("startTime") LocalDateTime startTime);

    /**
     * 统计指定天数内的罚款总额
     *
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 罚款总额
     */
    @Query("SELECT SUM(f.fineAmount) FROM Fine f WHERE f.createdTime BETWEEN :startTime AND :endTime")
    Optional<BigDecimal> sumFineAmountByPeriod(@Param("startTime") LocalDateTime startTime,
                                               @Param("endTime") LocalDateTime endTime);

    /**
     * 查找未支付的罚款记录
     *
     * @return 未支付罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.status = 'UNPAID'")
    List<Fine> findUnpaidFines();

    /**
     * 查找部分支付的罚款记录
     *
     * @return 部分支付罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.status = 'PARTIAL'")
    List<Fine> findPartialPaidFines();

    /**
     * 查找已支付的罚款记录
     *
     * @return 已支付罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.status = 'PAID'")
    List<Fine> findPaidFines();

    /**
     * 查找已减免的罚款记录
     *
     * @return 已减免罚款记录列表
     */
    @Query("SELECT f FROM Fine f WHERE f.status = 'WAIVED'")
    List<Fine> findWaivedFines();
}